package com.application.room.manage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.mina.core.buffer.IoBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.application.actor.manage.ActorManage;
import com.application.actor.pojo.Actor;
import com.application.race.manage.RaceManage;
import com.application.room.pojo.Room;
import com.core.action.ActionConstants;
import com.core.utils.Constants;
import com.core.utils.GameUtils;
import com.core.utils.PushDataUtils;
import com.core.utils.StringUtil;

public class RoomManage {
	private static final Logger log = LoggerFactory.getLogger(RoomManage.class);
	static int curentRoomId = 10000;

	private static Map<Integer, Room> rooms = new ConcurrentHashMap<Integer, Room>();
	public static boolean gameStart = true;

	public static void init() {

	
	}

	public static void update() {
		checkRooms();
		checkChange();
		checkApplyList();
	}

	private static void checkRooms() {
		// check tables
		synchronized (rooms) {
			Object[] keys = rooms.keySet().toArray();
			for (int i = 0; i < keys.length; i++) {
				int roomid = (Integer) keys[i];
				Room room = rooms.get(keys[i]);
				room.checkRoom();
				if (room.isEmpty) {
					room.lock = true;
					clearRoom(roomid);
				}
			}
		}
	}

	public static void clearRoom(int roomid) {
		roomChange(roomid, CHANGE_REMOVE_ROOM);
		rooms.remove(roomid);
	}

	public static void unlockRoom(int roomid) {
		synchronized (rooms) {

			if (rooms.containsKey(roomid)) {
				Room room = rooms.get(roomid);
				room.reset();
				roomChange(roomid, CHANGE_ROOM);
			}
		}
	}

	public static void reEnterRoom(Actor a) {
		synchronized (rooms) {

			if (rooms.containsKey(a.roomId)) {
				Room room = rooms.get(a.roomId);
				if(room.RS.actors.containsKey(a.getId()))
					room.reEnterRoom(a);
			} else {
				PushDataUtils.PushSimpleAction(a, ActionConstants.S2C_ACTION_GOTO_ROOM_LIST);
			}
		}
	}

	//

	private static Map<Integer, Actor> listUser = new ConcurrentHashMap<Integer, Actor>();

	public static void getRoomList(Actor a) {
		IoBuffer sendBuffer = IoBuffer.allocate(128);
		sendBuffer.setAutoExpand(true);
		sendBuffer.putInt(ActionConstants.S2C_ACTION_GET_ROOM_LIST);
		sendBuffer.putShort((short) rooms.size());
		for (Room r : rooms.values()) {
			sendBuffer.putInt(r.roomId);
			StringUtil.putString(sendBuffer, r.name, Constants.DEFAULT_CHARSET);
			StringUtil.putString(sendBuffer, r.psd, Constants.DEFAULT_CHARSET);
			sendBuffer.putInt(r.mode);
			sendBuffer.putInt(r.map);
			sendBuffer.put((byte) r.getUserNumber());
			sendBuffer.put(r.status);
			sendBuffer.putShort((short) r.minlv);
			sendBuffer.putShort((short) r.maxlv);
		}
		sendBuffer.flip();
		sendBuffer = GameUtils.Serialize(sendBuffer);
		a.getSession().write(sendBuffer);
		if (!listUser.containsKey(a.getId()))
			listUser.put(a.getId(), a);
	}

	static HashMap<Integer, Byte> changeInfo = new HashMap<Integer, Byte>();

	public static void roomChange(int roomId, byte change) {
		synchronized (changeInfo) {
			if (changeInfo.containsKey(roomId)) {
				if (change == CHANGE_ROOM)
					return;
			}
			changeInfo.put(roomId, change);
		}
	}

	public static final byte CHANGE_REMOVE_ROOM = 0;
	public static final byte CHANGE_ADD_ROOM = 1;
	public static final byte CHANGE_ROOM = 2;
	public static final int NO_CHANGE = -1;

	private static void checkChange() {

		synchronized (changeInfo) {

			if (changeInfo.size() <= 0)
				return;
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_REFRESH_ROOM_LIST);
			sendBuffer.putShort((short) changeInfo.size());

			Object[] keys = changeInfo.keySet().toArray();
			for (int i = 0; i < keys.length; i++) {
				int roomid = (Integer) keys[i];
				byte change = changeInfo.get(roomid);

				switch (change) {
				case CHANGE_ADD_ROOM:
					Room r = rooms.get(roomid);
					if (r == null) {
						sendBuffer.putInt(NO_CHANGE);
						continue;
					}
					sendBuffer.putInt(roomid);
					sendBuffer.put(change);
					StringUtil.putString(sendBuffer, r.name,
							Constants.DEFAULT_CHARSET);
					StringUtil.putString(sendBuffer, r.psd,
							Constants.DEFAULT_CHARSET);
					sendBuffer.putInt(r.mode);
					sendBuffer.putInt(r.map);
					sendBuffer.put((byte) r.getUserNumber());
					sendBuffer.put(r.status);
					sendBuffer.putShort((short) r.minlv);
					sendBuffer.putShort((short) r.maxlv);
					break;
				case CHANGE_ROOM:
					r = rooms.get(roomid);
					if (r == null) {
						sendBuffer.putInt(NO_CHANGE);
						continue;
					}
					sendBuffer.putInt(roomid);
					sendBuffer.put(change);
					sendBuffer.put((byte) r.getUserNumber());
					sendBuffer.put(r.status);
					break;
				case CHANGE_REMOVE_ROOM:
					sendBuffer.putInt(roomid);
					sendBuffer.put(change);
					break;
				}
			}
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			changeInfo.clear();
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(listUser.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_REFRESH_ROOM_LIST);

		}
	}

	public static void userApplyCreateRoom(Actor a, String roomName,
			String roomPsd, int mode, int map, int minlv, int maxlv) {
		int rid = -1;

		long now = System.currentTimeMillis();
		if (now - a.roomCreateTime < 10000) {
			PushDataUtils.PushSimpleAction(a, ActionConstants.S2C_ACTION_CREATE_ROOM_FAILD);
			return;
		} else {
			a.roomCreateTime = now;
		}
		rid = curentRoomId;
		curentRoomId++;
		Room room = new Room(a,rid, roomName, roomPsd, mode, map,
				minlv, maxlv);
		rooms.put(rid, room);
		// this.creaters.put(rid,uid);
		if (listUser.containsKey(a.getId()))
			listUser.remove(a.getId());
		roomChange(rid, CHANGE_ADD_ROOM);

	}

	public static void userKickOutRoom(Actor creater, int uid) {
		synchronized (rooms) {
			Actor user = ActorManage.getOnlineActor(uid);
			if (rooms.containsKey(creater.roomId)) {
				Room room = rooms.get(creater.roomId);
				if (room.kickOutFromRoom(creater, user)) {
					roomChange(user.roomId, CHANGE_ROOM);
					user.roomId = -1;
					user.chatmode = 0;
				}

			}
		}
	}

	public static void kickOutRoom(int roomid) {
		synchronized (rooms) {

			if (rooms.containsKey(roomid)) {
				Room room = rooms.get(roomid);
				room.kikOutRoom();

			}
		}
	}

	public static void userApplyEnterRoom(Actor a, int roomid) {
		synchronized (rooms) {
			Room room = rooms.get(roomid);

			if (room != null &&!room.lock && room.actorEnterRoom(a) ) {
				roomChange(roomid, CHANGE_ROOM);

				if (listUser.containsKey(a.getId()))
					listUser.remove(a.getId());
			} else {
				PushDataUtils.PushSimpleAction(a, ActionConstants.S2C_ACTION_ENTER_ROOM_FAILD);
			}

		}
	}

 

	public static void userOutofRoomList(Actor a) {
		synchronized (listUser) {
			if (listUser.containsKey(a.getId()))
				listUser.remove(a.getId());
		}

	}

	public static void userOutofRoom(Actor a) {
		synchronized (rooms) {
			if (rooms.containsKey(a.roomId)) {
				Room room = rooms.get(a.roomId);
				room.userOutofRoom(a);
				roomChange(a.roomId, CHANGE_ROOM);
				a.roomId = -1;
				a.chatmode = 0;
			}
		}
	}

	public static void actorOffline(Actor a) {
		synchronized (rooms) {
			 
			if (rooms.containsKey(a.roomId)) {
				Room room = rooms.get(a.roomId);
				room.offline(a);
				roomChange(a.roomId, CHANGE_ROOM);
				a.roomId = -1;
				a.chatmode = 0;
			}
			userOutofRoomList(a);
		}
	}

	public static boolean userApplyChangeSeat(Actor a, int seatid) {
		synchronized (rooms) {
		 
			if (rooms.containsKey(a.roomId)) {
				Room room = rooms.get(a.roomId);
				return room.userChangeSeat(a, seatid);
			}
		}
		return false;

	}

	public static boolean userApplyReady(Actor a) {

		log.info("in userApplyReady:" + a.getId());
		synchronized (rooms) {
		 
			if (rooms.containsKey(a.roomId)) {
				Room room = rooms.get(a.roomId);
				return room.userReady(a);
			}
		}
		return false;

	}

	public static boolean userApplyAbort(Actor a) {
		synchronized (rooms) {
			if (rooms.containsKey(a.roomId)) {
				Room room = rooms.get(a.roomId);
				return room.userAbort(a);
			}
		}
		return false;

	}

	public static void userApplyMatchRoom(Actor a) {
		int roomid = -1;
		int maxUser = 0;
		synchronized (rooms) {
			Object[] keys = rooms.keySet().toArray();
			for (int i = 0; i < keys.length; i++) {
				int rid = (Integer) keys[i];
				Room room = rooms.get(rid);
				if (room.lock)
					continue;
				if (room.hasPsd)
					continue;
				if (room.RS.isFull())
					continue;
				if (room.RS.getUserNumber() > maxUser) {
					maxUser = room.RS.getUserNumber();
					roomid = room.roomId;
				}
			}
			if (roomid < 0) {
				PushDataUtils.PushSimpleAction(a, ActionConstants.S2C_ACTION_MATCH_ROOM_FAILD);
			} else {
				userApplyEnterRoom(a, roomid);
			}
		}

	}

	static ArrayList<Integer> applyList = new ArrayList();

	public static void applyGameStart(int roomid) {
		synchronized (applyList) {

			applyList.add(roomid);
		}
	}

	public static void checkApplyList() {

		synchronized (applyList) {
			if (applyList.size() > 0) {

				int roomid = applyList.get(0);
				applyList.remove(0);
				Room room = rooms.get(roomid);

				if (RaceManage.applyCreateRacingRoom(room)) {
					room.roomCreated();
				} else {
					room.roomCraeateFailed();
				}

			}
		}

	}

}
